package ink.xiaobaibai.controller.buy;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import ink.xiaobaibai.common.AddTimeTaskBo;
import ink.xiaobaibai.common.MySecurity;
import ink.xiaobaibai.common.TimedTask;
import ink.xiaobaibai.entity.AdminUser;
import ink.xiaobaibai.entity.BuyOzoneDevice;
import ink.xiaobaibai.entity.BuyTimedTask;
import ink.xiaobaibai.response.ResponseFormat;
import ink.xiaobaibai.service.IAdminUserService;
import ink.xiaobaibai.service.IBuyOzoneDeviceService;
import ink.xiaobaibai.service.IBuyTimedTaskService;
import ink.xiaobaibai.service.IJumpService_V2;
import ink.xiaobaibai.service.monthly.IDelayTimedTaskService;
import ink.xiaobaibai.serviceOxy.buy.IDeviceBuyControlService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @description: 购买业务机器控制层
 * @author: 小白白
 * @create: 2021-06-13
 **/

@RestController
@RequestMapping("/buy/device")
@Api(tags = "购买业务机器控制层")
public class BuyDeviceController {

    @Autowired
    private IBuyOzoneDeviceService buyOzoneDeviceService;

    @Autowired
    private IBuyTimedTaskService buyTimedTaskService;

    @Autowired
    private IDelayTimedTaskService delayTimedTaskService;

    @Autowired
    private IJumpService_V2 jumpService_v2;

    @Autowired
    private IDeviceBuyControlService deviceBuyControlService;

    @Autowired
    private IAdminUserService adminUserService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final String BUY_DEVICE_OPEN = "buy_device_open:";

    /**
     * 查看自己的机器
     */
    @GetMapping("/list")
    @ApiOperation("查看自己购买的机器")
    public ResponseFormat list() {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<BuyOzoneDevice> q1 = new QueryWrapper<>();
        q1.select("id", "device_code", "admin_user_id");
        q1.eq("client_user_id", userId);
        q1.eq("can_use", true);
        List<BuyOzoneDevice> list = this.buyOzoneDeviceService.list(q1);

        if (list.size() == 0) {
            return ResponseFormat.success(list);
        }

        // 对应负责人信息
        List<Integer> userIds = list.stream().map(BuyOzoneDevice::getAdminUserId).collect(Collectors.toList());
        QueryWrapper<AdminUser> q2 = new QueryWrapper<>();
        q2.select("user_name", "user_phone");
        q2.in("id", userIds);
        List<AdminUser> adminUserList = this.adminUserService.list(q2);
        Map<Integer, AdminUser> adminUserMap = adminUserList.stream().collect(Collectors.toMap(AdminUser::getId, u -> u, (v1, v2) -> v2));

        List<Integer> deviceIds = list.stream().map(BuyOzoneDevice::getId).collect(Collectors.toList());
        List<BuyTimedTask> buyTimedTasks = this.batchEnableTime(deviceIds);
        Map<Integer, BuyTimedTask> buyTimedTaskMap = buyTimedTasks.stream().collect(Collectors.toMap(t -> t.getDeviceId(), t -> t, (v1, v2) -> v2));

        for (BuyOzoneDevice ozoneDevice : list) {
            AdminUser adminUser = adminUserMap.get(ozoneDevice.getAdminUserId());
            if (adminUser == null) {
                adminUser = this.adminUserService.getNameAndPhone(ozoneDevice.getAdminUserId());
                adminUserMap.put(ozoneDevice.getAdminUserId(), adminUser);
            }
            ozoneDevice.setAdminName(adminUser.getUserName());
            ozoneDevice.setAdminPhone(adminUser.getUserPhone());
            BuyTimedTask buyTimedTask = buyTimedTaskMap.get(ozoneDevice.getId());
            if (buyTimedTask != null && buyTimedTask.getOpen()) {
                ozoneDevice.setStatus("定时中");
            } else {
                String deviceStopTime = this.getDeviceStopTime(ozoneDevice.getId());
                if (deviceStopTime != null) {
                    ozoneDevice.setStatus("运行中");
                    ozoneDevice.setStopTime(deviceStopTime);
                } else {
                    ozoneDevice.setStatus("空闲中");
                }
            }
        }

        return ResponseFormat.success(list);
    }

    /**
     * 机器详细信息
     */
    @GetMapping("/item/{id}")
    @ApiOperation("机器的详细信息")
    public ResponseFormat itemById(@PathVariable("id") Integer deviceId) {
        QueryWrapper<BuyOzoneDevice> q1 = new QueryWrapper<>();
        q1.select("device_code", "admin_user_id", "oxygen_id");
        q1.eq("id", deviceId);
        BuyOzoneDevice buyOzoneDevice = this.buyOzoneDeviceService.getOne(q1);
        // 机器负责人信息
        AdminUser adminUser = this.adminUserService.getNameAndPhone(buyOzoneDevice.getAdminUserId());
        buyOzoneDevice.setAdminName(adminUser.getUserName());
        buyOzoneDevice.setAdminPhone(adminUser.getUserPhone());

        QueryWrapper<BuyTimedTask> q2 = new QueryWrapper<>();
        q2.eq("device_id", deviceId);
        BuyTimedTask timedTask = this.buyTimedTaskService.getOne(q2);

        if (timedTask != null && timedTask.getOpen()) {
            buyOzoneDevice.setStatus("定时中");
        } else {
            String deviceStopTime = this.getDeviceStopTime(deviceId);
            if (deviceStopTime != null) {
                buyOzoneDevice.setStopTime(deviceStopTime);
                buyOzoneDevice.setStatus("运行中");
            } else {
                buyOzoneDevice.setStatus("空闲中");
            }
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("buyOzoneDevice", buyOzoneDevice);
        jsonObject.put("timeTask", timedTask);
        return ResponseFormat.success(jsonObject);
    }

    /**
     * 启动自己的机器
     */
    @GetMapping("/open")
    @ApiOperation("启动自己的机器")
    public ResponseFormat openMyDevice(@RequestParam("deviceId") Integer deviceId,
                                       @RequestParam("seconds") Integer seconds) {
        if (seconds <= 0) {
            return ResponseFormat.failure("错误的时间设置");
        }
        ResponseFormat responseFormat = this.validDevice(deviceId);
        if (responseFormat.getCode() == 1) {
            return responseFormat;
        }
        this.deviceBuyControlService.open(deviceId, seconds);
        this.runDeviceRecord(deviceId, seconds);
        return ResponseFormat.success();
    }

    /**
     * 停止自己的机器
     */
    @GetMapping("/close")
    @ApiOperation("关闭自己的机器")
    public ResponseFormat closeMyDevice(@RequestParam("deviceId") Integer deviceId) {
        ResponseFormat responseFormat = this.validDevice(deviceId);
        if (responseFormat.getCode() == 1) {
            return responseFormat;
        }
        this.deviceBuyControlService.close(deviceId);
        this.stopDeviceRecord(deviceId);
        return ResponseFormat.success();
    }

    /**
     * 当前机器的定时任务
     */
    @GetMapping("/timed-task/{deviceId}")
    @ApiOperation("查看当前机器的定时任务")
    public ResponseFormat getTimedTaskByDeviceId(@PathVariable("deviceId") Integer deviceId) {
        QueryWrapper<BuyTimedTask> q1 = new QueryWrapper<>();
        q1.eq("device_id", deviceId);
        BuyTimedTask timedTask = this.buyTimedTaskService.getOne(q1);
        return ResponseFormat.success(timedTask);
    }

    /**
     * 给自己的机器添加定时任务
     */
    @PostMapping("/timed-task/add")
    @ApiOperation("为某台机器设置定时任务。 || 和修改是一体的,再次添加时,会删除后再添加")
    public ResponseFormat addTimeTask(@RequestBody AddTimeTaskBo timeTaskBo) {
        //先查验自己是否拥有此台机器? 先删除后添加
        Integer userId = MySecurity.getUserId();
        Integer deviceId = timeTaskBo.getDeviceId();
        QueryWrapper<BuyOzoneDevice> q1 = new QueryWrapper<>();
        q1.eq("client_user_id", userId);
        q1.eq("id", deviceId);
        if (this.buyOzoneDeviceService.count(q1) == 0) {
            return ResponseFormat.fail("未拥有此台机器");
        }
        //默认删除
        QueryWrapper<BuyTimedTask> q2 = new QueryWrapper<>();
        q2.eq("device_id", deviceId);
        this.buyTimedTaskService.remove(q2);
        //再添加
        BuyTimedTask buyTimedTask = new BuyTimedTask(deviceId);
        TimedTask timedTask = new TimedTask();
        for (AddTimeTaskBo.TimeSlot slot : timeTaskBo.getList()) {
            if (!timedTask.addTimeNode(slot.getStartDate(), slot.getEndDate())) {
                return ResponseFormat.fail("时间段不符合规则");
            }
        }
        buyTimedTask.setTimedTask(timedTask);
        buyTimedTask.setOpen(false);
        this.buyTimedTaskService.save(buyTimedTask);
        return ResponseFormat.success();
    }

    /**
     * 开关定时任务
     */
    @GetMapping("/time-task/open/{id}")
    @ApiOperation("改变自己的定时任务。  ||    启动则关闭  关闭则启动")
    public ResponseFormat openTimeTask(@PathVariable("id") Integer id) {
        Integer userId = MySecurity.getUserId();
        BuyTimedTask buyTimedTask = this.buyTimedTaskService.getById(id);
        if (buyTimedTask == null) {
            //定时任务不存在
            return ResponseFormat.fail("无效操作");
        }
        QueryWrapper<BuyOzoneDevice> q1 = new QueryWrapper<>();
        q1.eq("id", buyTimedTask.getDeviceId());
        q1.eq("client_user_id", userId);
        if (this.buyOzoneDeviceService.count(q1) == 0) {
            //机器不可用
            return ResponseFormat.fail("无效操作");
        }
        //启动则关闭  关闭则启动
        if (buyTimedTask.getOpen()) {
            //启动状态,则关闭
            this.delayTimedTaskService.closeBuyTimeTask(buyTimedTask);
        } else {
            this.stopDeviceRecord(buyTimedTask.getDeviceId());
            //关闭状态,则启动
            this.delayTimedTaskService.openBuyTimeTask(buyTimedTask);
        }
        return ResponseFormat.success();
    }

    private ResponseFormat validDevice(Integer deviceId) {
//        if(!jumpService_v2.checkBuyDeviceOnLine(deviceId)){
//            return ResponseFormat.fail("机器不在线上");
//        }
        Integer userId = MySecurity.getUserId();
        QueryWrapper<BuyOzoneDevice> q1 = new QueryWrapper<>();
        q1.select("client_user_id", "can_use");
        q1.eq("id", deviceId);
        BuyOzoneDevice ozoneDevice = this.buyOzoneDeviceService.getOne(q1);
        if (!ozoneDevice.getCanUse()) {
            return ResponseFormat.fail("当前机器未审核,暂不可用");
        }
        if (!userId.equals(ozoneDevice.getClientUserId())) {
            return ResponseFormat.fail("不可操控他人机器");
        }
        QueryWrapper<BuyTimedTask> q2 = new QueryWrapper<>();
        q2.select("open");
        q2.eq("device_id", deviceId);
        BuyTimedTask timedTask = this.buyTimedTaskService.getOne(q2);
        if (timedTask != null && timedTask.getOpen()) {
            return ResponseFormat.fail("定时任务启动中,不支持当前操作");
        }
        return ResponseFormat.success();
    }

    /**
     * 检测是否开启了定时
     */
    private boolean enableTime(Integer deviceId) {
        QueryWrapper<BuyTimedTask> q1 = new QueryWrapper<>();
        q1.eq("device_id", deviceId);
        q1.eq("open", true);
        return this.buyTimedTaskService.count(q1) == 1;
    }

    /**
     * 是否开启了定时任务(批量)
     */
    private List<BuyTimedTask> batchEnableTime(List<Integer> ids) {
        QueryWrapper<BuyTimedTask> q1 = new QueryWrapper<>();
        q1.select("device_id", "open");
        q1.in("device_id", ids);
        return this.buyTimedTaskService.list(q1);
    }

    /**
     * 单次启动记录
     */
    private void runDeviceRecord(Integer deviceId, Integer seconds) {
        this.stringRedisTemplate.opsForValue().set(BUY_DEVICE_OPEN + deviceId, DateUtils.addSeconds(new Date(), seconds).toString(), seconds + 10, TimeUnit.SECONDS);
    }

    /**
     * 单次停止
     */
    private void stopDeviceRecord(Integer deviceId) {
        this.stringRedisTemplate.delete(BUY_DEVICE_OPEN + deviceId);
    }

    /**
     * 如果没开启定时,还剩多久时间停止
     */
    private String getDeviceStopTime(Integer deviceId) {
        return this.stringRedisTemplate.opsForValue().get(BUY_DEVICE_OPEN + deviceId);
    }

}
